package at.ac.ait.archistar.backendserver;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.ssl.SslHandler;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.net.ssl.SSLEngine;
import at.ac.ait.archistar.trustmanager.SSLContextFactory;
import at.archistar.bft.messages.AbstractCommand;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* This class is responsible for sending messages to all replicas currently
* within the replica system.
*
* @author andy
*/
public class ServerServerCommunication {
/**
* mapping from replica id -> port. Note: currently only connections to localhost are supported
*/
private final Map<Integer, Integer> serverList;
/**
* opened channels
*/
private final Set<Channel> channels;
/**
* my server/replica Id -- this is used so that we are not connecting to
* ourself
*/
private int myServerId = -1;
private EventLoopGroup loopGroup = null;
public ServerServerCommunication(int myId, Map<Integer, Integer> serverList, EventLoopGroup elg) {
this.serverList = serverList;
this.channels = new HashSet<>();
this.myServerId = myId;
this.loopGroup = elg;
}
/**
* connects to all replicas
*
* @throws InterruptedException
*/
@SuppressFBWarnings("SIC_INNER_SHOULD_BE_STATIC_ANON")
public void connect() throws InterruptedException {
for (Entry<Integer, Integer> e : this.serverList.entrySet()) {
int replicaId = e.getKey();
int replicaPort = e.getValue();
if (replicaId != myServerId) {
Bootstrap b = new Bootstrap();
b.group(loopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
// enable SSL/TLS support
SSLEngine engine = SSLContextFactory.getClientContext().createSSLEngine();
engine.setUseClientMode(true);
ch.pipeline().addLast(
new SslHandler(engine),
new ObjectEncoder(),
new ObjectDecoder(OzymandiasServer.maxObjectSize, ClassResolvers.cacheDisabled(null)));
}
});
/* wait till server is connected */
ChannelFuture f = null;
do {
f = b.connect("127.0.0.1", replicaPort);
f.await();
} while (!(f.isDone() && f.isSuccess()));
this.channels.add(f.sync().channel());
}
}
}
/**
* sends a message to all connected replicas
*
* @param cmd the to be sent message
*/
public void send(AbstractCommand cmd) {
for (Channel channel : this.channels) {
channel.writeAndFlush(cmd);
}
}
}